package cn.shengchao.rule.engine;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import cn.shengchao.base.lock.DistributedLock;
import cn.shengchao.base.lock.ZLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @program: examstarapi
 * @description: 规则管理器
 * @author: Xiong weiqiang
 * @create: 2025-04-07 21:11
 */
@Component
public class RuleManager {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private DistributedLock distributedLock;

    /**
     * 加载所有规则
     * @return
     */
   public List<IRule> getAllRules(){
       List<Object> list =redisTemplate.opsForHash().values(RuleEngine.RULE_ENGINE_RULE_CONTENT_LIST_KEY);
       return CollUtil.isEmpty(list)? List.of():list.stream().map(o -> (IRule)o).toList();
   }

    /**
     * 初始化规则引擎，会有多个应用同时加载规则，所以需要加锁
     * @param addRules
     */
   public void cleanAndLoadRules(List<IRule> addRules){
       ZLock zLock=null;
       try {
           zLock=distributedLock.lock(RuleEngine.RULE_ENGINE_LOCK_KEY+"0");
           if (zLock!=null) {
               if (!redisTemplate.hasKey(RuleEngine.RULE_ENGINE_LOAD_KEY)) {
                   redisTemplate.opsForValue().set(RuleEngine.RULE_ENGINE_LOAD_KEY, "0");
                   redisTemplate.delete(RuleEngine.RULE_ENGINE_RULE_CONTENT_LIST_KEY);
                   System.out.println("规则引擎初始化：加载规则条数" + addRules.size() + "条");
                   if (CollUtil.isNotEmpty(addRules)){
                       addRules.forEach(iRule ->
                               redisTemplate.opsForHash().put(RuleEngine.RULE_ENGINE_RULE_CONTENT_LIST_KEY, iRule.getId().toString(), iRule));
                   }
                   System.out.println("规则引擎初始化完成：规则条数" + getAllRules().size() + "条");
                   redisTemplate.opsForValue().set(RuleEngine.RULE_ENGINE_LOAD_KEY, "1");
               } else {
                   System.out.println("规则引擎正在加载中");
                   List<IRule> list = getAllRules();
                   if (CollUtil.isEmpty(list)||list.size()!=addRules.size()){
                       redisTemplate.delete(RuleEngine.RULE_ENGINE_LOAD_KEY);
                       cleanAndLoadRules(addRules);
                   }else{
                       int i=0;
                       while (i<5) {
                           if (redisTemplate.hasKey(RuleEngine.RULE_ENGINE_LOAD_KEY) && "1".equals(redisTemplate.opsForValue().get(RuleEngine.RULE_ENGINE_LOAD_KEY))) {
                               System.out.println("规则引擎加载完毕：规则条数" + getAllRules().size() + "条");
                               return;
                           } else {
                               Thread.sleep(2000L);
                               System.out.println("规则引擎在其他应用加载");
                               i++;
                           }
                       }
                       redisTemplate.delete(RuleEngine.RULE_ENGINE_LOAD_KEY);
                       System.out.println("规则引擎加载超时，由本级初始化....");
                       cleanAndLoadRules(addRules);
                   }
               }
           }else {
               System.out.println("规则引擎获取操作锁失败");
           }
       } catch (Exception e) {
           throw new RuntimeException(e);
       }finally {
           try {
               if (zLock!=null){
                   zLock.close();
               }
           } catch (Exception e) {
               e.printStackTrace();
           }
       }
   }

    /**
     * 调用规则引擎替换规则，本身是dubbo调用，所以正常情况下是单例
     * @param r
     */
   public void replaceRule(IRule r){
       ZLock zLock=null;
       try {
           zLock = distributedLock.lock(RuleEngine.RULE_ENGINE_LOCK_KEY+r.getId());
           if (zLock != null) {
               List<IRule> list0 = getAllRules();
               System.out.println("规则数据清理替换前：" + list0.size()+"条"+ JSONUtil.toJsonStr(list0));
               // 删除规则
               redisTemplate.opsForHash().delete(RuleEngine.RULE_ENGINE_RULE_CONTENT_LIST_KEY,r.getId().toString());
               List<IRule> rules = getAllRules();
               System.out.println("规则数据替换清理后：" + rules.size()+"条"+ JSONUtil.toJsonStr(rules));
               if (!rules.contains(r)){
                   redisTemplate.opsForHash().put(RuleEngine.RULE_ENGINE_RULE_CONTENT_LIST_KEY,r.getId().toString(),r);
               }
               List<IRule> rules1 = getAllRules();
               System.out.println("规则数据替换后：" + rules1.size()+"条"+ JSONUtil.toJsonStr(rules1));
           }
       } catch (Exception e) {
           throw new RuntimeException(e);
       }finally {
           try {
               if (zLock != null) {
                   zLock.close();
               }
           } catch (Exception e) {
               e.printStackTrace();
           }
       }
   }
    /**
     * 调用规则引擎清理规则，本身是dubbo调用，所以正常情况下是单例
     * @param r
     */
    public void clearRule(IRule r){
        ZLock zLock=null;
        try {
            zLock = distributedLock.lock(RuleEngine.RULE_ENGINE_LOCK_KEY+r.getId());
            if (zLock != null) {
                List<IRule> rules1 = getAllRules();
                System.out.println("规则数据变化前：" + rules1.size()+"条"+JSONUtil.toJsonStr(rules1));
                // 删除规则
                redisTemplate.opsForHash().delete(RuleEngine.RULE_ENGINE_RULE_CONTENT_LIST_KEY,r.getId().toString());
                List<IRule> rules = getAllRules();
                System.out.println("规则状态改变删除：" + r.getName());
                System.out.println("规则数据变化后：" + rules.size()+"条"+JSONUtil.toJsonStr(rules));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if (zLock != null) {
                    zLock.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
}